/* jshint node: true */
/* global io, Hammer, $ */
"use strict";

var touchElem = document.getElementById("touchpad");
var socket = io();
var delta = null;
var moving = false;
var ori = "portrait";
var control = "touch";
var passcode = "";
var supportsVibrate = "vibrate" in navigator;
var pos = { x: 0, y: 0, cmd: null, pw: "" };
/**
 * pass `pos` object to socket.emit('mouse', pos) function
 *
 * {Object} pos
 * {integer} pos.x mouse x offset
 * {integer} pos.y mouse y offset
 * {string} pos.cmd key command or mouse click (not implemented yet)
 */
var socketTimer;
var missionTimer;
var emitMouse = function(x, y, cmd) {
  pos.x = x;
  pos.y = y;
  pos.cmd = cmd;
  pos.pw = passcode;
  if (socketTimer && cmd !== "click") {
    clearTimeout(missionTimer);
    missionTimer = setTimeout(function() {
      socket.emit("mouse", pos);
    }, 10);
    return;
  }
  clearTimeout(missionTimer);
  socketTimer = setTimeout(function() {
    socketTimer = null;
  }, 10);
  socket.emit("mouse", pos);
};

// receive msg
//socket.on('mouse', function(msg) {
//console.log(msg);
//console.info(msg.x + ',' + msg.y);
//});

var handlePan = function(eventName, e) {
  if (e.type == eventName + "start") {
    delta = null;
    moving = true;
    console.log("start " + eventName);
    emitMouse(0, 0, eventName + "start");
  }
  if (e.type == eventName + "end") {
    delta = null;
    moving = false;
    emitMouse(0, 0, eventName + "end");
  }
  if (moving && delta != null) {
    emitMouse(e.deltaX - delta.x, e.deltaY - delta.y, eventName);
  }
  delta = { x: e.deltaX, y: e.deltaY };
};

var mc = new Hammer.Manager(touchElem);
// mc.add(
//   new Hammer.Pan({
//     event: "move",
//     threshold: 0,
//     pointers: 1,
//     direction: Hammer.DIRECTION_ALL
//   })
// );
// mc.add(
//   new Hammer.Pan({
//     event: "scroll",
//     threshold: 0,
//     pointers: 2,
//     direction: Hammer.DIRECTION_ALL
//   })
// );

// mc.add(new Hammer.Tap({ event: "click", pointers: 1 }));
mc.add(new Hammer.Tap({ event: "rightclick", pointers: 2 }));

// mc.on("movestart moveend moveup movedown moveleft moveright", function(e) {
//   if (control !== "motion") {
//     handlePan("move", e);
//   }
// });
// mc.on(
//   "scrollstart scrollend scrollup scrolldown scrollleft scrollright",
//   function(e) {
//     handlePan("scroll", e);
//   }
// );
// mc.on("dragstart dragend dragup dragdown dragleft dragright", function(e) {
//   handlePan("drag", e);
// });
// mc.on("click", function(e) {
//   console.info("click");
//   navigator.vibrate([10]);
//   if (control === "present") {
//     emitMouse(0, 0, "right");
//   } else {
//     emitMouse(0, 0, "click");
//   }
// });
let flag = false;
let fingers = 0;
let force = 0;
let lastX = 0;
let lastY = 0;
let startX = 0;
let startY = 0;
let hasMove = false;
let leftDown = false;
let lastTime = 0;
let speed = 0;
let speedX = 0;
let speedY = 0;
let a = 0;

let doubleTimer;
const doubleLimit = 150;
let clickTimer;
let distanceX = 0;
let distanceY = 0;
let startDisX = 0;
let startDisY = 0;
let mode = "";

let wintab = false;

let slipTimer;

let multiLock;
let multiRange = 30;
function getTouchInfo(e) {
  let x = 0,
    y = 0,
    disX = 0,
    disY = 0;
  for (let i = 0; i < e.touches.length; i++) {
    const { pageX: px, pageY: py } = e.touches[i];
    x += px;
    y += py;
  }
  x /= e.touches.length;
  y /= e.touches.length;
  for (let i = 0; i < e.touches.length; i++) {
    const { pageX: px, pageY: py } = e.touches[i];
    disX += Math.abs(px - x);
    disY += Math.abs(py - y);
  }
  disX /= e.touches.length;
  disY /= e.touches.length;
  return { x, y, disX, disY };
}
document.addEventListener("touchstart", e => {
  cancelAnimationFrame(slipTimer);
  fingers = e.touches.length;
  if (fingers === 1) {
    clearTimeout(clickTimer);
    hasMove = false;
    force = e.touches[0].force;
    const { pageX: x, pageY: y } = e.touches[0];
    startX = lastX = x;
    startY = lastY = y;
    speed = speedX = speedY = 0;
    lastTime = e.timeStamp;
    if (doubleTimer) {
      leftDown = true;
      doubleTimer = false;
      emitMouse(0, 0, "dragstart");
    } else {
      doubleTimer = setTimeout(() => {
        doubleTimer = null;
      }, doubleLimit);
    }
  } else if (fingers >= 2) {
    const { x, y, disX, disY } = getTouchInfo(e);
    startDisX = distanceX = disX / e.touches.length;
    startDisY = distanceY = disY / e.touches.length;
    startX = lastX = x;
    startY = lastY = y;
    multiLock = clearTimeout(multiLock);
  }
});
document.addEventListener("touchmove", e => {
  if (fingers === 1) {
    const { pageX: x, pageY: y } = e.touches[0];
    const dX = x - lastX;
    const dY = y - lastY;
    const currentSpeed = Math.hypot(dX, dY) / (e.timeStamp - lastTime);
    a = currentSpeed - speed;
    // const f = e.touches[0].force;
    // if (!leftDown) {
    //   if (Math.hypot(dX, dY) < 2)
    //     if (
    //       // (force < 3 && f > force * 1.7 && f < force * 2.5) ||
    //       f > 6 &&
    //       f < 8
    //     ) {
    //       if (!flag) {
    //         navigator.vibrate([20]);
    //         flag = true;
    //         emitMouse(0, 0, "click");
    //       }
    //     } else if (/* (force < 3 && f >= force * 2.5) || */ f >= 8) {
    //       navigator.vibrate([50]);
    //       emitMouse(0, 0, "dragstart");
    //       leftDown = true;
    //     } else {
    //       flag = false;
    //     }
    // }
    let addSpeed = 1;
    if (a > 0) {
      addSpeed = a + 1;
    }
    emitMouse(dX * addSpeed, dY * addSpeed, "move");
    if (!hasMove && Math.hypot(x - startX, y - startY) > 3) hasMove = true;
    lastX = x;
    lastY = y;
    lastTime = e.timeStamp;
    speed = currentSpeed;
  } else if (fingers === 2) {
    const { pageX: x1, pageY: y1 } = e.touches[0];
    const { pageX: x2, pageY: y2 } = e.touches[1];
    const disX = Math.abs(x2 - x1);
    const disY = Math.abs(y2 - y1);
    const x = (x2 + x1) / 2;
    const y = (y2 + y1) / 2;
    const dX = x - lastX;
    const dY = y - lastY;
    const ddX = disX - distanceX;
    const ddY = disY - distanceY;
    speedX = dX / (e.timeStamp - lastTime);
    speedY = dY / (e.timeStamp - lastTime);
    emitMouse(dX, dY, "scroll");
    /* switch (mode) {
      case "scroll":
        emitMouse(dX, dY, "scroll");
        break;
      case "scale":
        break;
      default:
        // if (Math.hypot(x - startX, y - startY) > 0.9 * 1.414) {
          // if (
          //   (disX-startDisX < -0.9 && disY - startDisY < -0.9) ||
          //   (disX - startDisX > 0.9 && disY - startDisY > 0.9)
          // )
          //   mode = "scale";
          // else  mode = "scroll";
        } */
    // }
    distanceX = disX;
    distanceY = disY;
    lastX = x;
    lastY = y;
    lastTime = e.timeStamp;
  } else if (fingers === 3) {
    const { x, y, disX, disY } = getTouchInfo(e);
    if (multiLock) {
      lastX = x;
      lastY = y;
      distanceX = disX;
      distanceY = disY;
      return;
    }
    let operateFlag = false;
    if (y - lastY < -multiRange) {
      emitMouse(0, 0, "missionview");
      wintab = !wintab;
      // fingers = 0;
      operateFlag = true;
    } else if (x - lastX < -multiRange) {
      emitMouse(0, 0, "nextDesktop");
      // fingers = 0;
      operateFlag = true;
    } else if (x - lastX > multiRange) {
      emitMouse(0, 0, "prevDesktop");
      // fingers = 0;
      operateFlag = true;
    } else if (y - lastY > multiRange * 1.5) {
      if (wintab) {
        emitMouse(0, 0, "missionview");
      } else {
        emitMouse(0, 0, "desktop");
      }
      wintab = false;
      // fingers = 0;
      operateFlag = true;
    }
    if (operateFlag) {
      lastX = x;
      lastY = y;
      distanceX = disX;
      distanceY = disY;
      multiLock = setTimeout(() => {
        multiLock = null;
      }, 500);
    }
  }
});
document.addEventListener("touchend", e => {
  if (e.touches.length === 0) {
    if (leftDown) {
      emitMouse(0, 0, "dragend");
      leftDown = false;
      wintab = false;
    }
    if (fingers === 1) {
      if (!hasMove) {
        emitMouse(0, 0, "dragstart");
        leftDown = true;
        wintab = false;
        clickTimer = setTimeout(() => {
          navigator.vibrate([20]);
          emitMouse(0, 0, "dragend");
          wintab = false;
        }, doubleLimit);
      }
    } else if (fingers === 2) {
      slip();
      // switch(mode){
      // }
    }
    mode = "";
  }
});
function slip() {
  let moveFlag = false;
  let x = 0;
  let y = 0;
  if (Math.abs(speedX) > 0.1) {
    moveFlag = true;
    x = speedX * 10;
    speedX *= 0.95;
  }
  if (Math.abs(speedY) > 0.1) {
    moveFlag = true;
    y = speedY * 10;
    speedY *= 0.95;
  }
  if (moveFlag) {
    emitMouse(x, y, "scroll");
    slipTimer = requestAnimationFrame(slip);
  }
}
mc.on("rightclick", function(e) {
  console.info("rightclick");
  if (control === "present") {
    emitMouse(0, 0, "left");
  } else {
    emitMouse(0, 0, "rightclick");
  }
});
// menu functions
document.body.requestFullscreen =
  document.body.requestFullScreen ||
  document.body.webkitRequestFullScreen ||
  document.body.mozRequestFullScreen ||
  document.body.msRequestFullScreen;
document.cancelFullscreen =
  document.exitFullscreen ||
  document.webkitExitFullscreen ||
  document.mozCancelFullScreen ||
  document.msExitFullscreen;

$("#fullscreen-toggle").click(function() {
  if (!document.fullscreen) {
    document.body.requestFullscreen();
    ori = "landscape";
    lockOrientation();
  } else {
    document.cancelFullscreen();
  }
});

var lockOrientation = function() {
  if (document.fullscreen) {
    screen.lockOrientation =
      screen.lockOrientation ||
      screen.mozLockOrientation ||
      screen.msLockOrientation;
    // update menu
    if (ori === "portrait") {
      $("#portrait").removeClass("hidden");
      $("#landscape").addClass("hidden");
    } else {
      $("#landscape").removeClass("hidden");
      $("#portrait").addClass("hidden");
    }

    if (screen.lockOrientation) {
      return screen.lockOrientation(ori + "-primary");
    } else {
      return screen.orientation.lock(ori + "-primary");
    }
  } else {
    // update menu
    $("#portrait").addClass("hidden");
    $("#landscape").addClass("hidden");
  }
};

$(window).on(
  "fullscreenchange mozfullscreenchange webkitfullscreenchange " +
    "msfullscreenchange",
  function() {
    document.fullscreen =
      (document.mozFullScreen ||
        document.webkitIsFullScreen ||
        document.msFullscreen) === true;
    $("#fullscreen-toggle").prop("checked", document.fullscreen);
    lockOrientation();
  }
);

// orientation
$("#portrait").click(function() {
  ori = "landscape";
  lockOrientation();
});
$("#landscape").click(function() {
  ori = "portrait";
  lockOrientation();
});

// modes
$("#touch-ctrl").click(function() {
  control = "touch";
  // update menu
  $("#touch-ctrl").addClass("active");
  $("#motion-ctrl").removeClass("active");
  $("#present-ctrl").removeClass("active");
});
$("#motion-ctrl").click(function() {
  control = "motion";
  // update menu
  $("#touch-ctrl").removeClass("active");
  $("#motion-ctrl").addClass("active");
  $("#present-ctrl").removeClass("active");
});
$("#present-ctrl").click(function() {
  control = "present";
  // update menu
  $("#touch-ctrl").removeClass("active");
  $("#motion-ctrl").removeClass("active");
  $("#present-ctrl").addClass("active");
});

$("#passcode").click(function() {
  passcode = prompt("Enter a passcode");
});

$("#about").click(function() {
  if (
    confirm(
      "Webby Mouse: Air mouse made with full web technology.\n" +
        "Visit our web site for more information?"
    )
  ) {
    open("https://github.com/gasolin/webbymouse");
  }
});

window.addEventListener("deviceorientation", function(e) {
  if (control === "motion") {
    var x = e.gamma;
    var y = e.beta;
    y = y > 90 ? 90 : y;
    y = y < -90 ? -90 : y;

    x += 90;
    y += 90;
    emitMouse(x, y, "motion");
  }
});
